﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security;
using System.Text;
using ComHlp.ContentClasses;
using ComHlp.enums;
using ComHlp.Exceptions;

namespace ComHlp.Classes.Net
{
    internal static class ComHelper
    {
        /// <summary> Build paket from string </summary>
        /// <param name="codePage"></param>
        /// <param name="compression"></param>
        /// <param name="data2Send"></param>
        /// <returns></returns>
        internal static byte[] BuildPaket(ItxCodepage codePage, ItxCompression compression, byte[] data2Send)
        {
            // build paket before sending, adding final 0x00 for i5
            byte[] data;
            // add 0x00 if i5host
            if (codePage == ItxCodepage.Cp273
                || compression == ItxCompression.ClientV5)
            {
                data = new byte[data2Send.Length + 1];
                data[data.Length - 1] = 0x00;
            }
            else
                data = new byte[data2Send.Length];


            try
            {
                data2Send.CopyTo(data, 0);
            }
            catch (ArgumentNullException){}
            catch (ArrayTypeMismatchException){}
            catch (RankException){}
            catch (ArgumentOutOfRangeException){}
            catch (InvalidCastException){}

            // length of the paket (excluding length) for the data header
            short dataLength = (short)data.Length;
            byte[] length = BitConverter.GetBytes(dataLength);
            length = new[] { length[1], length[0] };

            // write to memroy strea for adding data
            using (MemoryStream ms = new MemoryStream())
            {
                try
                {
                    ms.Write(length, 0, 2);
                    ms.Write(data, 0, data.Length);
                }
                catch (IOException){}
                
                ms.Position = 0;

                // return memorystream
                return ms.ToArray();
            }
        }

        /// <summary> Get the local ip address </summary>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"><paramref name="localEndPoint"/> is <see langword="null" />.</exception>
        /// <exception cref="CommunicationException">Unable to get ip address.</exception>
        internal static string GetIpAddress(EndPoint localEndPoint)
        {
            if (localEndPoint == null) throw new ArgumentNullException(nameof(localEndPoint));

            string ipAddr = "000000000000";
            // get ipaddress from local endpoint 
            IPEndPoint ipend = (IPEndPoint)localEndPoint;
            if (ipend.AddressFamily != AddressFamily.InterNetwork)
                return ipAddr;

            string tmpIpAddr;
            try
            {
                tmpIpAddr = ipend.Address.ToString();
            }
            catch (SocketException exc)
            {
                throw new CommunicationException("Unable to get ip address.", exc);
            }
            // split and build needed
            string[] ipParts = tmpIpAddr.Split('.');
            StringBuilder sbIp = new StringBuilder();

            if (ipParts.Length == 4)
            {
                foreach (string part in ipParts)
                {
                    switch (part.Length)
                    {
                        case 2:
                            sbIp.Append("0" + part);
                            break;
                        case 1:
                            sbIp.Append("00" + part);
                            break;
                        default:
                            sbIp.Append(part);
                            break;
                    }
                }
            }
            while (sbIp.Length < 18)
                sbIp.Append(' ');
            ipAddr = sbIp.ToString();
            return ipAddr;
        }

        /// <summary> retrieve temporary filename </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        /// <exception cref="CommunicationException">Condition.</exception>
        internal static string GetTempFile(string filePath = null)
        {
            // get temporary fieldname
            string tempPath;
            try
            {
                tempPath = Path.GetTempPath();
            }
            catch (SecurityException exc)
            {
                throw new CommunicationException(exc, "Unable to retrieve temp directory: {0}", exc.Message);
            }

            // so let us extract the filename
            string pureFileName = Path.GetFileName(filePath);
            if (string.IsNullOrEmpty(pureFileName))
                pureFileName = Path.GetRandomFileName();

            string finalPath = Path.Combine(tempPath, pureFileName);
            return finalPath;
        }

        internal static void ParseReceivedServerMessageType(StringBuilder sbResponse, ItxServerMessage serverMessage)
        {
            if (sbResponse.Length <= 34)
                return;

            string serverMessageType = sbResponse.ToString(30, 4);
            switch (serverMessageType)
            {
                case "SERV":
                    serverMessage.MessageType = ItxServerMessageType.ConnectServResponse;
                    break;
                case "FRM ":
                case "FRM4":
                    serverMessage.MessageType = ItxServerMessageType.FormDef;
                    break;
                case "BS  ":
                    serverMessage.MessageType = ItxServerMessageType.ScreenContent;
                    break;
                case "BS01":
                    serverMessage.MessageType = ItxServerMessageType.ScreenContentCompressed;
                    break;
                case "LV  ":
                    serverMessage.MessageType = ItxServerMessageType.ListView;
                    break;
                case "OK  ":
                    serverMessage.MessageType = ItxServerMessageType.ServerAck;
                    break;
                case "FG  ":
                    serverMessage.MessageType = ItxServerMessageType.FileGet;
                    break;
                case "FGB ":
                    serverMessage.MessageType = ItxServerMessageType.FileGetBinary;
                    break;
                case "GRA ":
                    serverMessage.MessageType = ItxServerMessageType.Graphics;
                    break;
                case "EXT ":
                    serverMessage.MessageType = ItxServerMessageType.ExternalData;
                    break;
                case "Z001":
                    serverMessage.MessageType = ItxServerMessageType.LicenseData;
                    break;
                case "Z002":
                    serverMessage.MessageType = ItxServerMessageType.VersionData;
                    break;
                case "MI2 ":
                    serverMessage.MessageType = ItxServerMessageType.ProgramExplorer;
                    break;
                case "FI1 ":
                    serverMessage.MessageType = ItxServerMessageType.Favorites;
                    break;
                default:
                    serverMessage.MessageType = ItxServerMessageType.Unknown;
                    break;
            }
        }
    }
}